﻿using System;
using BalanceManager.Model;
using System.Collections.Generic;
using System.Linq;

namespace BalanceManager.Services
{
    public class DataService : IDataService
    {
        private bool NeedCreateEntity(int id)
        {
            return id <= 0;
        }

        #region Item methods
        private List<Item> _itemsList;
        public List<Item> Items
        {
            get
            {
                if (_itemsList == null)
                {
                    using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
                    {
                        _itemsList = db.Items.ToList();
                    }
                }
                return _itemsList;
            }
        }

        public void SaveItem(Item item)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                if (NeedCreateEntity(item.Id))
                {
                    db.Items.InsertOnSubmit(item);
                    db.SubmitChanges();
                    this.Items.Add(item);
                }
                else
                {
                    var dbItem = db.Items.First(o => o.Id == item.Id);
                    dbItem.Name = item.Name;
                    db.SubmitChanges();
                }
            }
        }

        public void DeleteItem(int id)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var dbItem = db.Items.First(o => o.Id == id);
                db.Items.DeleteOnSubmit(dbItem);
                db.SubmitChanges();
                this.Items.Remove(_itemsList.First(o => o.Id == id));
            }
        }

        public bool ItemHasChilds(Item item)
        {
            var entry = this.Items.FirstOrDefault(i => i.ParentId == item.Id);
            return entry != null;
        }

        public Item GetItemById(int id)
        {
            return this.Items.FirstOrDefault(i => i.Id == id);
        }
        #endregion

        #region FundFlows Methods

        public List<FundFlow> LoadFundFlows(DateTime dateFrom, DateTime dateTo, FlowType flowType)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var fundFlows = from ff in db.FundFlows
                    join item in db.Items on ff.ItemId equals item.Id
                    where ff.Date >= dateFrom && ff.Date <= dateTo && (ff.FlowType != FlowType.None || ff.FlowType == flowType)
                    select new
                    {
                        Id = ff.Id,
                        Amount = ff.Amount,
                        Date = ff.Date,
                        FlowType = ff.FlowType,
                        ItemId = ff.ItemId,
                        ItemName = item.Name
                    };

                var fundFlowsList = new List<FundFlow>();
                foreach (var fundFlow in fundFlows)
                {
                    fundFlowsList.Add(new FundFlow
                    {
                        Id = fundFlow.Id,
                        Amount = fundFlow.Amount,
                        Date = fundFlow.Date,
                        FlowType = fundFlow.FlowType,
                        ItemId = fundFlow.ItemId,
                        ItemName = fundFlow.ItemName
                    });
                }

                return fundFlowsList;
            }
        }

        public List<FundFlow> LoadFundFlows(DateTime dateFrom, DateTime dateTo)
        {
            return LoadFundFlows(dateFrom, dateTo, FlowType.None);
        }

        public void SaveFundFlow(FundFlow value)
        {
            if (value.FlowType == FlowType.None)
                throw new ArgumentException("Refused to save FlowType.None into database.", "value");

            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                if (NeedCreateEntity(value.Id))
                {
                    db.FundFlows.InsertOnSubmit(value);
                }
                else
                {
                    var entity = db.FundFlows.First(o => o.Id == value.Id);
                    entity.ItemId = value.ItemId;
                    entity.Amount = value.Amount;
                    entity.Date = value.Date;
                    entity.FlowType = value.FlowType;
                }
                var item = db.Items.Single(o => o.Id == value.ItemId);
                item.UpdateFrequency += 1;
                db.SubmitChanges();
            }
        }

        public bool ItemExistsInFundFlows(Item value)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var findeditem = db.FundFlows.FirstOrDefault(o => o.ItemId == value.Id);
                return findeditem != null;
            }
        }

        public FundFlow GetFundFlowById(int id)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var findeditem = db.FundFlows.FirstOrDefault(o => o.Id == id);
                return findeditem;
            }
        }

        public void DeleteFundFlow(int id)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var findeditem = db.FundFlows.FirstOrDefault(o => o.Id == id);
                db.FundFlows.DeleteOnSubmit(findeditem);
                db.SubmitChanges();
            }
        }

        public List<Item> RecentlyUsedItems(int maxCount)
        {
            using (BalanceManagerDataContext db = new BalanceManagerDataContext(BalanceManagerDataContext.DBConnectionString))
            {
                var items = db.Items.Where(o => o.UpdateFrequency > 1).Take(maxCount);
                var list = items.ToList();
                list.Sort((x, y) => x.UpdateFrequency.CompareTo(y.UpdateFrequency));
                return list;
            }
        }

        #endregion
    }

}
